package showtime.framework.algorithm.astar
{
	import showtime.framework.utils.AlgorithmUtility;
	
	import flash.geom.Point;

	/**
	 * Holds a two-dimensional array of Nodes methods to manipulate them, start node and end node for finding a path.
	 */
	public class MapModel implements IMapModel
	{
		private var _map:Array = null;
		private var _nodes:Array = null;
		public var cols:int = 0;
		public var rows:int = 0;
		
		/**
		 * Constructor.
		 */
		public function MapModel(map:Array)
		{
			cols = map.length;
			rows = map[0].length;
					
			_map = [];
			
			for(var i:int = 0; i < cols; i++)
			{
				_map[i] = [];
				for(var j:int = 0; j < rows; j++)
				{
					_map[i][j] = new Node(i, j, map[i][j] == 0);
				}
			}

		}
		
		/**
		 * Returns the node at the given coords.
		 * @param x The x coord.
		 * @param y The y coord.
		 */
		public function getNode(col:int, row:int):Node
		{
			if (_map != null)
			{
				return _map[col][row];
			}
			return null;
	
		}
		
		
		/**
		 * Sets the node at the given coords as walkable or not. 
		 * @param col
		 * @param row
		 * @param value
		 * 
		 */		
		public function setWalkable(col:int, row:int, value:Boolean):void
		{
			_map[col][row].walkable = value;
		}
		
	
		public function getNodesUnderPoint(xPos:Number, yPos:Number, exception:Array = null):Array
		{
			var result:Array = [];
			var xIsInt:Boolean = xPos % 1 == 0;
			var yIsInt:Boolean = yPos % 1 == 0;
			
			if(xIsInt && yIsInt)
			{
				result[0] = getNode( xPos - 1, yPos - 1);
				result[1] = getNode( xPos, yPos - 1);
				result[2] = getNode( xPos - 1, yPos);
				result[3] = getNode( xPos, yPos);
			}
			else if(xIsInt && !yIsInt)
			{
				result[0] = getNode(xPos - 1, int(yPos));
				result[1] = getNode(xPos, int(yPos));
			}
			else if(!xIsInt && yIsInt)
			{
				result[0] = getNode( int(xPos), yPos - 1);
				result[1] = getNode( int(xPos), yPos );
			}
			else
			{
				result[0] = getNode( int(xPos), int(yPos) );
			}
			
			if(exception && exception.length > 0)
			{
				for( var i:int=0; i<result.length; i++ )
				{
					if( exception.indexOf(result[i]) != -1 )
					{
						result.splice(i, 1);
						i--;
					}
				}
			}			
			return result;
		}
		
		/**
		 * 判断两节点之间是否存在障碍物 
		 * 
		 */		
		public function hasBarrier(startX:int, startY:int, endX:int, endY:int):Boolean
		{
	
			if( startX == endX && startY == endY )
			{
				return false;
			}
			
			var point1:Point = new Point( startX + 0.5, startY + 0.5 );
			var point2:Point = new Point( endX + 0.5, endY + 0.5 );
			
			var distX:Number = Math.abs(endX - startX);
			var distY:Number = Math.abs(endY - startY);									
			
			var loopDirection:Boolean = distX > distY ? true : false;

			var lineFuction:Function = null;
			
			var i:Number = 0;
			
			var loopStart:Number = 0;
			
			var loopEnd:Number = 0;
			
			var passedNodeList:Array = null;
			var passedNode:Node = null;
			
			if(loopDirection)
			{				
				lineFuction = AlgorithmUtility.getLineFunc(point1, point2, 0);
				
				loopStart = Math.min( startX, endX );
				loopEnd = Math.max( startX, endX );

				for( i=loopStart; i<=loopEnd; i++ )
				{
					if( i == loopStart )i += .5;

					var yPos:Number = lineFuction(i);

					passedNodeList = getNodesUnderPoint(i, yPos);
					for each( passedNode in passedNodeList )
					{
						if( passedNode.walkable == false )return true;
					}
					
					if( i == loopStart + .5 )i -= .5;
				}
			}
			else
			{
				lineFuction = AlgorithmUtility.getLineFunc(point1, point2, 1);
				
				loopStart = Math.min( startY, endY );
				loopEnd = Math.max( startY, endY );

				for( i=loopStart; i<=loopEnd; i++ )
				{
					if( i==loopStart )i += .5;

					var xPos:Number = lineFuction(i);
					
					passedNodeList = getNodesUnderPoint( xPos, i );
					
					for each( passedNode in passedNodeList )
					{
						if( passedNode.walkable == false )return true;
					}
					
					if( i == loopStart + .5 )i -= .5;
				}
			}

			return false;			
		}
		
		
	}
}